#include "SQLUnpivot.h"

#include "../../Exception/IllegalArgumentException.h"
#include "../../sql/visitor/SQLASTVisitor.h"
#include "../../utils/listTran.h"

SQLUnpivot_NullsIncludeType_ptr SQLUnpivot_NullsIncludeType::INCLUDE_NULLS = SQLUnpivot_NullsIncludeType_ptr(new SQLUnpivot_NullsIncludeType(1L << 1, make_string_ptr("INCLUDE_NULLS")));
SQLUnpivot_NullsIncludeType_ptr SQLUnpivot_NullsIncludeType::EXCLUDE_NULLS = SQLUnpivot_NullsIncludeType_ptr(new SQLUnpivot_NullsIncludeType(1L << 2, make_string_ptr("EXCLUDE_NULLS")));

SQLUnpivot::SQLUnpivot()
{
  items = std::make_shared<std::list<SQLExpr_ptr>>();
  pivotFor = std::make_shared<std::list<SQLExpr_ptr>>();
  pivotIn = std::make_shared<std::list<SQLSelectItem_ptr>>();
}

SQLUnpivot_NullsIncludeType::SQLUnpivot_NullsIncludeType(uint64_t mask, string_ptr name)
{
  this->mask = mask;
  this->name = name;
}

string_ptr SQLUnpivot_NullsIncludeType::toString(SQLUnpivot_NullsIncludeType_ptr type, bool ucase)
{
  if (SQLUnpivot_NullsIncludeType::INCLUDE_NULLS->equals(type))
  {
    return ucase ? make_string_ptr("INCLUDE NULLS") : make_string_ptr("include nulls");
  }
  if (SQLUnpivot_NullsIncludeType::EXCLUDE_NULLS->equals(type))
  {
    return ucase ? make_string_ptr("EXCLUDE NULLS") : make_string_ptr("exclude nulls");
  }

  throw new IllegalArgumentException();
}

bool SQLUnpivot_NullsIncludeType::equals(SQLUnpivot_NullsIncludeType_ptr type)
{
  return (this->mask == type->mask && this->name == type->name);
}

// std::map<u_int64_t, string_ptr > NullsIncludeType::str({{1, "INCLUDE_NULLS"}, {2, "EXCLUDE_NULLS"}});
// NullsIncludeType::NullsIncludeType()
// {
//   for (auto it = str.begin(); it != str.end(); ++it)
//   {
//     str_int[it->second] = it->first;
//   }
// }
// NullsIncludeType::_MyEnum &NullsIncludeType::operator=(NullsIncludeType::_MyEnum &val)
// {
//   _enum = val;
//   currstr = str.find((int)val)->second;
//   return _enum;
// }
// NullsIncludeType::_MyEnum &NullsIncludeType::operator=(NullsIncludeType &val)
// {
//   _enum = val._enum;
//   currstr = str.find((int)val._enum)->second;
//   return _enum;
// }
// BOOL_ptr NullsIncludeType::operator==(NullsIncludeType &rgt)
// {
//   return _enum == rgt._enum;
// }
// BOOL_ptr NullsIncludeType::operator==(_MyEnum &rgt)
// {
//   return _enum == rgt;
// }
// int NullsIncludeType::value()
// {
//   return (int)(_enum);
// }
// string_ptr  NullsIncludeType::toString()
// {
//   return currstr;
// }
// string_ptr  NullsIncludeType::toString(NullsIncludeType::_MyEnum &val, BOOL_ptr ucase)
// {
//   if (_MyEnum::INCLUDE_NULLS == val)
//   {
//     return ucase ? "INCLUDE NULLS" : "include nulls";
//   }
//   if (_MyEnum::EXCLUDE_NULLS == val)
//   {
//     return ucase ? "EXCLUDE NULLS" : "exclude nulls";
//   }
// }
// u_int64_t NullsIncludeType::of(string_ptr  type)
// {
//   if (type.empty())
//   {
//     return 0;
//   }
//   u_int64_t v = 0;
//   size_t flagSub = 0;
//   for (size_t i = 0; i < type.length(); i++)
//   {
//     if (type[i] == ',')
//     {
//       string_ptr  temp = type.substr(flagSub, i - flagSub);
//       if (str_int.find(temp) != str_int.end())
//         v |= str_int.find(temp)->second;
//       flagSub = i + 1;
//     }
//   }
//   if (type.length() > flagSub)
//   {
//     string_ptr  temp = type.substr(flagSub, type.length() - flagSub);
//     if (str_int.find(temp) != str_int.end())
//       v |= str_int.find(temp)->second;
//   }
//   return v;
// }

void SQLUnpivot::accept0(SQLASTVisitor_ptr v)
{
  if (v->visit(SharedObject(SQLUnpivot)))
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(this->items);
    acceptChild(v, tmp1);
    SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLExpr, SQLObject>(this->pivotFor);
    acceptChild(v, tmp2);
    SQLObject_list_ptr tmp3 = ListTran::tran_class<SQLSelectItem, SQLObject>(this->pivotIn);
    acceptChild(v, tmp3);
  }
  v->endVisit(SharedObject(SQLUnpivot));
}

SQLUnpivot_NullsIncludeType_ptr SQLUnpivot::getNullsIncludeType()
{
  return nullsIncludeType;
}

void SQLUnpivot::setNullsIncludeType(SQLUnpivot_NullsIncludeType_ptr nullsIncludeType)
{
  this->nullsIncludeType = nullsIncludeType;
}

SQLExpr_list_ptr SQLUnpivot::getPivotFor()
{
  return pivotFor;
}

SQLSelectItem_list_ptr SQLUnpivot::getPivotIn()
{
  return pivotIn;
}

SQLExpr_list_ptr SQLUnpivot::getItems()
{
  return this->items;
}

void SQLUnpivot::addItem(SQLExpr_ptr item)
{
  if (item != NULL)
  {
    item->setParent(SharedObject(SQLUnpivot));
  }
  this->items->emplace(this->items->end(), item);
}

SQLObject_ptr SQLUnpivot::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLUnpivot>(new SQLUnpivot());
  std::shared_ptr<SQLUnpivot> x = std::dynamic_pointer_cast<SQLUnpivot>(clone_tmp);
  // SQLUnpivot *x = new SQLUnpivot();

  x->setNullsIncludeType(nullsIncludeType);

  for (SQLExpr_ptr e : *this->items)
  {
    SQLExpr_ptr e2 = e;
    e2->setParent(x);
    x->getItems()->emplace(x->getItems()->end(), e2);
  }

  for (SQLExpr_ptr e : *this->pivotFor)
  {
    SQLExpr_ptr e2 = e;
    e2->setParent(x);
    x->getPivotFor()->emplace(x->getPivotFor()->end(), e2);
  }

  for (SQLSelectItem_ptr e : *this->pivotIn)
  {
    SQLSelectItem_ptr e2 = e;
    e2->setParent(x);
    x->getPivotIn()->emplace(x->getPivotIn()->end(), e2);
  }

  return x;
}
